package mq

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"time"

	"github.com/ammyhaber/seckill/pkg/mq"
	"github.com/ammyhaber/seckill/service/inventory/model"
	"github.com/ammyhaber/seckill/service/inventory/service"
)

// InventoryConsumer 库存消息消费者
type InventoryConsumer struct {
	inventoryLockService *service.InventoryLockService
	rabbitMQ             *mq.RabbitMQ
	stopChan             chan struct{}
	isRunning            bool
}

// NewInventoryConsumer 创建库存消息消费者
func NewInventoryConsumer(
	inventoryLockService *service.InventoryLockService,
	rabbitMQ *mq.RabbitMQ,
) *InventoryConsumer {
	return &InventoryConsumer{
		inventoryLockService: inventoryLockService,
		rabbitMQ:             rabbitMQ,
		stopChan:             make(chan struct{}),
	}
}

// Start 启动消费者
func (c *InventoryConsumer) Start() error {
	if c.isRunning {
		return nil
	}
	c.isRunning = true

	// 确保队列存在
	err := c.rabbitMQ.DeclareQueue("inventory_queue")
	if err != nil {
		return fmt.Errorf("声明队列失败: %w", err)
	}

	// 确保交换机存在
	err = c.rabbitMQ.DeclareExchange("inventory_exchange", "direct")
	if err != nil {
		return fmt.Errorf("声明交换机失败: %w", err)
	}

	// 绑定队列到交换机
	err = c.rabbitMQ.BindQueue("inventory_queue", "inventory_exchange", "inventory_key")
	if err != nil {
		return fmt.Errorf("绑定队列失败: %w", err)
	}

	// 启动消费者协程
	go c.consume()

	log.Println("库存消息消费者已启动")
	return nil
}

// Stop 停止消费者
func (c *InventoryConsumer) Stop() {
	if !c.isRunning {
		return
	}
	close(c.stopChan)
	c.isRunning = false
	log.Println("库存消息消费者已停止")
}

// consume 消费消息
func (c *InventoryConsumer) consume() {
	// 创建消费者
	msgs, err := c.rabbitMQ.Consume("inventory_queue", "inventory_consumer")
	if err != nil {
		log.Printf("创建消费者失败: %v\n", err)
		return
	}

	for {
		select {
		case <-c.stopChan:
			// 收到停止信号
			return
		case msg, ok := <-msgs:
			if !ok {
				// 通道已关闭
				log.Println("消费者通道已关闭")
				return
			}
			// 处理消息
			c.handleMessage(msg.Body)
			// 确认消息
			msg.Ack(false)
		}
	}
}

// handleMessage 处理消息
func (c *InventoryConsumer) handleMessage(body []byte) {
	// 解析消息
	var message model.InventoryMessage
	if err := json.Unmarshal(body, &message); err != nil {
		log.Printf("解析消息失败: %v\n", err)
		return
	}

	// 创建上下文
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// 根据消息类型处理
	switch message.MessageType {
	case model.MessageTypeLockInventory:
		// 处理锁定库存消息
		c.handleLockInventory(ctx, &message)
	case model.MessageTypeConfirmInventory:
		// 处理确认库存消息
		c.handleConfirmInventory(ctx, &message)
	case model.MessageTypeCancelInventory:
		// 处理取消库存消息
		c.handleCancelInventory(ctx, &message)
	default:
		log.Printf("未知消息类型: %s\n", message.MessageType)
	}
}

// handleLockInventory 处理锁定库存消息
func (c *InventoryConsumer) handleLockInventory(ctx context.Context, message *model.InventoryMessage) {
	log.Printf("处理锁定库存消息: %s, 订单ID: %s, 商品ID: %d\n", message.MessageID, message.OrderID, message.ProductID)

	// 构造请求
	req := &model.InventoryLockRequest{
		OrderID:   message.OrderID,
		ProductID: message.ProductID,
		Count:     message.Count,
	}

	// 锁定库存
	success, err := c.inventoryLockService.LockInventory(ctx, req)
	if err != nil {
		log.Printf("锁定库存失败: %v\n", err)
		return
	}

	if !success {
		log.Printf("库存不足，锁定失败, 订单ID: %s, 商品ID: %d\n", message.OrderID, message.ProductID)
		return
	}

	log.Printf("库存锁定成功, 订单ID: %s, 商品ID: %d\n", message.OrderID, message.ProductID)
}

// handleConfirmInventory 处理确认库存消息
func (c *InventoryConsumer) handleConfirmInventory(ctx context.Context, message *model.InventoryMessage) {
	log.Printf("处理确认库存消息: %s, 订单ID: %s, 商品ID: %d\n", message.MessageID, message.OrderID, message.ProductID)

	// 构造请求
	req := &model.InventoryLockConfirmRequest{
		OrderID:   message.OrderID,
		ProductID: message.ProductID,
	}

	// 确认库存
	err := c.inventoryLockService.ConfirmInventoryDeduction(ctx, req)
	if err != nil {
		log.Printf("确认库存失败: %v\n", err)
		return
	}

	log.Printf("库存确认成功, 订单ID: %s, 商品ID: %d\n", message.OrderID, message.ProductID)
}

// handleCancelInventory 处理取消库存消息
func (c *InventoryConsumer) handleCancelInventory(ctx context.Context, message *model.InventoryMessage) {
	log.Printf("处理取消库存消息: %s, 订单ID: %s, 商品ID: %d\n", message.MessageID, message.OrderID, message.ProductID)

	// 构造请求
	req := &model.InventoryLockCancelRequest{
		OrderID:   message.OrderID,
		ProductID: message.ProductID,
	}

	// 取消库存
	err := c.inventoryLockService.CancelInventoryDeduction(ctx, req)
	if err != nil {
		log.Printf("取消库存失败: %v\n", err)
		return
	}

	log.Printf("库存取消成功, 订单ID: %s, 商品ID: %d\n", message.OrderID, message.ProductID)
}
